/**
 * @file MRM_MCU.ino
 * @author UCAS-China 2022 hardware
 * @brief Control of NodeMCU
 *          The MRM_MCU stands for meal replacement maker(machine)'s micro controller unit
 *          
 *          use lowercase and _ for names
 * @version 0.4
 * @date 2022-10-9
 * 
 */

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <LittleFS.h>
#include <String.h>

#define SPWM_PIN D2                  // for pwm
#define MAX_SIZE 128
#define PARA_NUM 4
#define ANALOG_MAX 1024

const char *ssid = "UCAS-SEM-Power"; 
const char *password = "12345678";

ESP8266WebServer esp8266_server(80);    // webserver at port 80

char loop_setting = 0;

float freq; // Hz, so we can get the period
float max_v;// V
float min_v;// V
float time_int; // ms

float period; // ms


int number_of_dots; // how many dots in one period

unsigned short volts[MAX_SIZE];

String vars[PARA_NUM];

void setup() {
  pinMode(SPWM_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("");
  WiFi.softAP(ssid, password);
  Serial.print("Access Point: ");
  Serial.println(ssid);
  Serial.print("Password: ");
  Serial.println(password);
  Serial.print("IP address: ");
  Serial.println(WiFi.softAPIP());  // The IP address

  // start file system
  if(LittleFS.begin()){
    Serial.println("LittleFS Started.");
  } else {
    Serial.println("LittleFS Failed to Start.");
  }

  // start server 
  esp8266_server.on("/set_para", set_para); // main controlling part
  esp8266_server.onNotFound(handleUserRequest);
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop() {
  int i;
  if(!loop_setting)
    esp8266_server.handleClient();  // handle the request
  else
  {
    Serial.println("Start controlling");
    i = 0;
    while(1)
    {
      analogWrite(SPWM_PIN, volts[i]);
      i++;
      i%= number_of_dots;
      delay(time_int);
    }
  }
}

String fenge(String str,String fen,int index)
{
 int weizhi;
 String temps[str.length()];
 int i=0;
 do
 {
    weizhi = str.indexOf(fen);
    if(weizhi != -1)
    {
      temps[i] =  str.substring(0,weizhi);
      str = str.substring(weizhi+fen.length(),str.length());
      i++;
      }
      else {
        if(str.length()>0)
        temps[i] = str;
      }
 }
  while(weizhi>=0);

  if(index>i)return "-1";
  return temps[index];
}
// from https://blog.csdn.net/luckyfungi/article/details/119182284

void set_para() {
    int i;
    char rv;
    String target_arg = esp8266_server.arg("para");
    for(i = 0; i<PARA_NUM; i++)
    {
      vars[i] = fenge(target_arg,":",i);
    }
    freq = vars[0].toFloat();
    min_v = vars[1].toFloat();
    max_v = vars[2].toFloat();
    time_int = vars[3].toFloat();
    String send_back_str = String(freq) + ":" + String(min_v) + ":" + String(max_v) + ":" + String(time_int);
    Serial.print("Want to set at:");
    Serial.println();
    // send the state back
    rv = initialize_controlling();
    if(rv == 1)
      send_back_str = "[retry]Too much dots!";
    else if(rv == 2)
      send_back_str = "[retry] negtive vars";
    // else if(rv == 1)
    esp8266_server.send(200,"text/plain",send_back_str);
}

int initialize_controlling() {

  int i;
  if(freq <= 0 || min_v < 0 || max_v < 0 || time_int < 0)
    return 2;
  period = 1000 / freq; // in ms
  number_of_dots = period / time_int;
  if(number_of_dots > MAX_SIZE)
    return 1; // not OK
  for(i = 0; i<number_of_dots; i++)
  {
    volts[i] = (short)(ANALOG_MAX * (sin(i/(double)number_of_dots * M_PI * 2) * (max_v - min_v) / 2 + (max_v + min_v) / 2));
  }

  loop_setting = 1;
  return 0; // OK
}


void handleUserRequest() {
  String webAddress = esp8266_server.uri(); // Uniform Resource Identifier
  bool fileReadOK = handleFileRead(webAddress);
  if(!fileReadOK) {
    esp8266_server.send(404,"text/plain","404 Not Found");
  }
}

// The function below are from tai-chi maker: http://www.taichi-maker.com/
// And we modified the file system into LittleFS
bool handleFileRead(String path) {
  Serial.println("Request:"+path);
  if(path.endsWith("/")) {
    path = "/index.html"; // default page
  }
  String contentType = getContentType(path);
  if(LittleFS.exists(path)) {
    File file = LittleFS.open(path,"r");
    esp8266_server.streamFile(file,contentType);  // File the file and send by WIFI
    file.close();
    return true;
  }
  else
    return false;
}

// The function below are from tai-chi maker: http://www.taichi-maker.com/
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}
